﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Consul;
using M.Core.RmoteCall;
using M.Core.RmoteCall.ApiCall;
using M.Core.RmoteCall.Log;
using M.Core.RmoteCall.RpcCall;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Thrift;
using Thrift.Protocols;
using Thrift.Server;
using Thrift.Transports;
using Thrift.Transports.Server;

namespace M.Core
{
    // 客户端实现接口的一些注入IOC，和初始化Consul客户服务以供内部使用
    public static class ClientExtensions
    {
        //public class ExceptionHandlingMiddleware
        //{
        //    private readonly RequestDelegate _next;

        //    public ExceptionHandlingMiddleware(RequestDelegate next)
        //    {
        //        _next = next;
        //    }

        //    public async Task Invoke(HttpContext context)
        //    {
        //        try
        //        {
        //            await _next(context);
        //        }catch(TApplicationException ex)
        //        {
        //            await HandleExceptionAsync(context, ex);
        //        }catch(TProtocolException ex)
        //        {
        //            await HandleExceptionAsync(context, ex);
        //        }
        //        catch (Exception ex)
        //        {
        //            //if (ex.StackTrace.Contains("Thrift.Transports.Client"))
        //            //{
        //            //    await HandleExceptionAsync(context, ex);
        //            //}
        //            //var statusCode = context.Response.StatusCode;
        //            throw ex;
        //        }
        //    }
        //    private Task HandleExceptionAsync(HttpContext context, Exception exception)
        //    {
        //        ErrorHandler.handler(exception);

        //        return Task.FromResult(0);
        //        //return context.Response.WriteAsync("ERROR");
        //    }
        //}

        public class ServiceStartMiddleware
        {
            private readonly RequestDelegate _next;

            public ServiceStartMiddleware(RequestDelegate next)
            {
                _next = next;
            }

            public async Task Invoke(HttpContext context)
            {
                if (ServiceDiscovery.Init)
                {
                    await _next(context);
                }
            }
        }

        /// <summary>
        /// 注入WebApi远程调用接口
        /// </summary>
        /// <param name="services"></param>
        /// <param name="ptype"></param>
        /// <returns></returns>
        public static IServiceCollection AddApiService(this IServiceCollection services, Type ptype)
        {
            var array = ptype.Assembly.GetTypes().Where(i => i.GetInterface("M.Core.RmoteCall.IRemoteCallService") != null && i.GetInterface("IAsync") == null);

            foreach (var item in array)
            {
                var type = RemoteCallProxy.Create(typeof(RemoteCallProxy), item);

                services.AddSingleton(item, type);
            }
            services.AddSingleton<ConsulClient>();
            services.AddSingleton<ServiceDiscovery>();
            services.AddSingleton<CallLog>();


            return services;
        }

        /// <summary>
        /// 注入Thrift接口服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="ptype"></param>
        /// <returns></returns>
        public static IServiceCollection AddRpcCallService(this IServiceCollection services, Type ptype)
        {
            var array = ptype.Assembly.GetTypes().Where(i => i.GetInterface("M.Core.RmoteCall.IRemoteCallService") != null && i.GetInterface("IAsync") != null && i.GetInterface("IAsync").IsNested);

            foreach (var item in array)
            {
                var type = RemoteCallProxy.Create(typeof(RemoteCallProxy), item);

                services.AddSingleton(item, type);
            }
            services.AddSingleton<ConsulClient>();
            services.AddSingleton<ServiceDiscovery>();
            services.AddSingleton<CallLog>();

            return services;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseCallService(this IApplicationBuilder builder)
        {
            builder.UseMiddleware<ServiceStartMiddleware>();

            //builder.UseMiddleware<ExceptionHandlingMiddleware>();
            //初始化服务发现
            var serviceDiscovery = builder.ApplicationServices.GetService<ServiceDiscovery>();
            var log = builder.ApplicationServices.GetService<CallLog>();
            var services = builder.ApplicationServices.CreateScope().ServiceProvider;
            var lifeTime = services.GetService<IApplicationLifetime>();

            lifeTime.ApplicationStarted.Register(() =>
            {
                RpcServiceKeeper.GetInstance();
                serviceDiscovery.StartSyncServiceList();
            });

            return builder;
        }
    }
}
